//-----------------------------------------------------------------------
// <copyright file="CodeCoverageTest.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
// </copyright>
// <author>Simon Bell</author>
// <email>v-sibell</email>
// <date>2004-03-23</date>
// <summary>Unit test for the code coverage Tasks.</summary>
//-----------------------------------------------------------------------

namespace Microsoft.Sdc.Tasks.Test
{
    using System;
    using System.Globalization;
    using System.IO;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using Microsoft.Sdc.Tasks.Configuration;
    using Microsoft.Sdc.Tasks;
    using Microsoft.Build.Framework;

    /// <summary>
    /// Unit test for the Code Coverage Tasks
    /// </summary>
    [TestClass]
    public class CodeCoverageTest
    {
        

        bool testConfigFileModifications = true;

        private string _initialConfigFile;
        private string _initialConfigFileBackup;

        public CodeCoverageTest()
        {
        }

        [TestMethod]
        [Ignore]//("Remove hard coded paths")]
        public void TestCodeCoverageTasks()
        {
            string configPath = TaskTestUtilities.CreateTempFolder();
            string reportDirectory = TaskTestUtilities.CreateTempFolder();

            if (testConfigFileModifications)
            {
                BackupExistingCoverageEyeConfigurationFile();
            }

            try
            {
                if (testConfigFileModifications)
                {
                    //Create a code coverage config file creation at default location
                    string defaultConfigFile = CreateCodeCoverageConfiguration(String.Empty);

                    //Create one at a specific location
                    string specificConfigFile = CreateCodeCoverageConfiguration(configPath);

                    //Add an assembly to it (default location used)
                    string assemblyToAdd = "TestAssembly.dll";
                    AddAssemblyToConfigFile(String.Empty, assemblyToAdd.ToLower(CultureInfo.InvariantCulture), reportDirectory);
                }

                //Start code coverage
                StartCodeCoverage();

                //NUnit
                RunNunitOnTestAssembly();

                //Stop code coverage
                StopCodeCoverage();

                //Merge reports
                MergeReports(reportDirectory);

            }
            finally
            {
                if (testConfigFileModifications)
                {
                    RestoreExistingCoverageEyeConfigurationFile();
                }

                Directory.Delete(configPath, true);
                //Directory.Delete(reportDirectory, true);
            }
        }

        [TestMethod]
        [Ignore]//("These may be preventing code coverage from running properly")]
        public void TestUninitializedAddAssemblyTaskFails()
        {
            Tasks.CodeCoverage.AddAssembly task = new Tasks.CodeCoverage.AddAssembly();
           

            try
            {
                bool taskReturnValue = task.Execute();
                Assert.Fail("Uninitialised tasks should not succeed.");
            }
            catch (ApplicationException)
            {
                Console.WriteLine("Correctly threw exception");
                Console.WriteLine(((PseudoBuildEngine) task.BuildEngine).PreviousMessage);
            }

        }

        [TestMethod]
        [Ignore]//("These may be preventing code coverage from running properly")]
        public void TestUninitialisedCreateTaskFails()
        {
            Tasks.CodeCoverage.Create task = new Tasks.CodeCoverage.Create();
           

            try
            {
                bool taskReturnValue = task.Execute();
                Assert.Fail("Uninitialised tasks should not succeed.");
            }
            catch (ApplicationException)
            {
                Console.WriteLine("Correctly threw exception");
                Console.WriteLine(((PseudoBuildEngine) task.BuildEngine).PreviousMessage);
            }

        }

        //Start and stop should both succeed

        [TestMethod]
        [Ignore]//("These may be preventing code coverage from running properly")]
        public void TestUninitializedMergeTaskFails()
        {
            Tasks.CodeCoverage.MergeReports task = new Tasks.CodeCoverage.MergeReports();
           

            try
            {
                bool taskReturnValue = task.Execute();
                Assert.Fail("Uninitialised tasks should not succeed.");
            }
            catch (ApplicationException)
            {
                Console.WriteLine("Correctly threw exception");
                Console.WriteLine(((PseudoBuildEngine) task.BuildEngine).PreviousMessage);
            }

        }

        private string CreateCodeCoverageConfiguration(string inputConfigPath)
        {
            Tasks.CodeCoverage.Create createTask = new Tasks.CodeCoverage.Create();
           
            createTask.Path = inputConfigPath;

            bool createTaskSuccess = createTask.Execute();

            Assert.IsTrue(createTaskSuccess, "CodeCoverageConfigCreated");

            //This should now have created a code coverage config file.
            string configPath = createTask.Path;
            string configFileLocation = configPath + "CoverageConfiguration.xml";

            Assert.IsTrue(System.IO.File.Exists(configFileLocation), "Could not find code coverage config file");
            Console.WriteLine("CodeCoverage config file created at: " + configFileLocation + " for input path: " + inputConfigPath);

            string configContents = System.IO.File.ReadAllText(configFileLocation);
            Assert.IsTrue(configContents.IndexOf("CoverageConfiguration") > 0, "Found expected config text");

            return configFileLocation;
        }

        private void AddAssemblyToConfigFile(string inputConfigPath, string assemblyToAdd, string reportDirectory)
        {
            Tasks.CodeCoverage.AddAssembly addAssemblyTask = new Tasks.CodeCoverage.AddAssembly();
           
            addAssemblyTask.AssemblyName = assemblyToAdd;
            addAssemblyTask.Path = inputConfigPath;
            addAssemblyTask.ReportDirectory = reportDirectory;

            bool taskSuccess = addAssemblyTask.Execute();

            Assert.IsTrue(addAssemblyTask.AssemblyName == assemblyToAdd, "AssemblyTaskParameters");
            Assert.IsTrue(addAssemblyTask.ReportDirectory == reportDirectory, "AssemblyTaskParameters");

            Assert.IsTrue(taskSuccess, "AddAssemblyTask");

            string configPath = addAssemblyTask.Path;
            string configFileLocation = configPath + "CoverageConfiguration.xml";

            Assert.IsTrue(System.IO.File.Exists(configFileLocation), "Could not find code coverage config file");

            string configContents = System.IO.File.ReadAllText(configFileLocation);
            Console.WriteLine(configContents);
            Assert.IsTrue(configContents.IndexOf(assemblyToAdd) > 0, "Found expected assembly text");
            Assert.IsTrue(configContents.IndexOf(reportDirectory) > 0, "Found expected assembly text");

        }

        private void StartCodeCoverage()
        {
            Tasks.CodeCoverage.Start startTask = new Tasks.CodeCoverage.Start();
           
            bool taskSuccess = startTask.Execute();
            Assert.IsTrue(taskSuccess, "StartCodeCoverageTask");
        }

        private void StopCodeCoverage()
        {
            Tasks.CodeCoverage.Stop stopTask = new Tasks.CodeCoverage.Stop();
           
            bool taskSuccess = stopTask.Execute();
            Assert.IsTrue(taskSuccess, "StopCodeCoverageTask");
        }

        private void MergeReports(string reportDirectory)
        {
            Tasks.CodeCoverage.MergeReports mergeTask = new Tasks.CodeCoverage.MergeReports();
            
            //mergeTask.FileSpec = 
            mergeTask.OutputPath = reportDirectory;
            //mergeTask.ReportFilenameMatch = 

            bool taskSuccess = mergeTask.Execute();
            Assert.IsTrue(taskSuccess, "MergeCodeCoverageTask");

            //Ensure there are two files in the report directory:
            Console.WriteLine("Merging files to : " + reportDirectory);

            Assert.IsTrue(System.IO.File.Exists(reportDirectory + "\\Transform.xsl"), "PostMergeXslFileExists");
            Assert.IsTrue(Directory.GetFiles(reportDirectory, "Report*.xml").Length == 1, "PostMergeReportFileExists");
        }

        private void RunNunitOnTestAssembly()
        {
            string outputDirectory = TaskTestUtilities.CreateTempFolder();
            string outputFilename = TaskTestUtilities.CreateTempFileInFolder("nunitOutput", outputDirectory);

            try
            {
                Tools.NUnit task = new Tools.NUnit();
               

                string toolPath = @"C:\Program Files\NUnit V2.1\bin\nunit-console.exe";
                string version = "2.1";
                string assemblyName = @"C:\Projects\Microsoft.Sdc.Configuration\Main\Src\Solutions\MainSolution\Microsoft.Sdc.Tasks.Configuration.Tasks.Test.AssemblyTest\bin\Debug\TestAssembly.dll";

                //NB: REMOVE .Path property from task
                task.ToolPath = toolPath;

                task.Assemblies = new string[] { assemblyName };
                task.Version = version;

                task.OutputFolder = outputDirectory;

                Assert.IsTrue(task.Assemblies[0] == assemblyName, "TaskProperties");
                Assert.IsTrue(task.ToolPath == toolPath, "TaskProperties");
                Assert.IsTrue(task.Version == version, "TaskProperties");
                Assert.IsTrue(task.OutputFolder == outputDirectory, "TaskProperties");

                bool taskReturnValue = task.Execute();
                Assert.IsTrue(taskReturnValue, "TestNunit");
            }
            finally
            {
                Directory.Delete(outputDirectory, true);
            }
        }

        private void BackupExistingCoverageEyeConfigurationFile()
        {
            _initialConfigFile = DefaultCoverageConfigurationFilePath();
            _initialConfigFileBackup = _initialConfigFile + ".bak";

            if (System.IO.File.Exists(_initialConfigFile))
            {
                try
                {
                    System.IO.File.Copy(_initialConfigFile, _initialConfigFileBackup);
                    Console.WriteLine("Backed up existing config file");
                    Assert.IsTrue(System.IO.File.Exists(_initialConfigFileBackup), "BackedupConfig");
                }
                catch (Exception)
                {
                    Assert.Fail("Unable to back up existing config");
                }
            }
        }

        private void RestoreExistingCoverageEyeConfigurationFile()
        {
            if (System.IO.File.Exists(_initialConfigFile))
            {
                try
                {
                    System.IO.File.Delete(_initialConfigFile);
                }
                catch (Exception e)
                {
                    Assert.Fail("Unable to delete temp config - " + e.ToString());
                }
            }

            if (System.IO.File.Exists(_initialConfigFileBackup))
            {
                try
                {
                    System.IO.File.Copy(_initialConfigFileBackup, _initialConfigFile);
                    System.IO.File.Delete(_initialConfigFileBackup);
                }
                catch (Exception e)
                {
                    Assert.Fail("Unable to restore previous config - " + e.ToString());
                }
            }
        }

        private string DefaultCoverageConfigurationFilePath()
        {
            string path = String.Empty;

            string key1 = @"CLSID\{18656C37-035D-41CD-82C2-85DEF2DD5F7B}\InprocServer32";
            Microsoft.Win32.RegistryKey regKey = null;
            regKey = Microsoft.Win32.Registry.ClassesRoot.OpenSubKey(key1);

            if (regKey != null)
            {
                string regValue = null;
                regValue = regKey.GetValue(null).ToString();
                if (regValue != null)
                {
                    string pathToConfig = String.Empty;

                    System.IO.FileInfo fileinfo = new FileInfo(regValue);
                    pathToConfig = (fileinfo.DirectoryName + "\\Configuration\\");
                    path = pathToConfig;
                }
                else
                {
                    Assert.Fail("CodeCoverage NotRegistered");
                }
                regKey.Close();
                path = path + "CoverageConfiguration.xml";
            }
            else
            {
                Assert.Fail("CodeCoverage NotRegistered");
            }
            return path;
        }
    }
}